﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using IntoNails.Infrastructure.DataAccess;
using IntoNails.Infrastructure.Extensions;
using IntoNails.Models;

namespace IntoNails.DataAccess
{
    public class CategoryRepository : AbstractDataRepository<Category, Guid>, ICategoryRepository, IDataFileRepository
    {
        public CategoryRepository(string dataFilePath)
        {
            this.DataFilePath = dataFilePath;
        }

        #region Overrides of AbstractDataRepository<Category,Guid>

        public override Category Get(Guid uniqueCode)
        {
            return this.InnerDataList.SingleOrDefault(category => category.UniqueCode == uniqueCode);
        }

        public override IList<Category> GetRawItemList()
        {
            return this.InnerDataList;
        }

        public override IEnumerable<Category> Get(Func<Category, bool> predicate)
        {
            return this.InnerDataList.Where(predicate);
        } 

        public override void Add(Category item)
        {
            if (null == item)
            {
                this.OnDataAdded(new DataEventArgs<Category>(new ArgumentNullException("item")));
            }
            else if (this.InnerDataList.Contains(item))
            {
                this.OnDataAdded(new DataEventArgs<Category>(false));
            }
            else
            {
                this.InnerDataList.Add(item);
                this.OnDataAdded(new DataEventArgs<Category>(true));
            }
        }

        public override void Remove(Guid uniqueCode)
        {
            Category removedCategory = this.Get(uniqueCode);
            if (null == removedCategory)
            {
                this.OnDataRemoved(new DataEventArgs<Category>(new ArgumentNullException("removedCategory")));
            }
            else
            {
                this.InnerDataList.Remove(removedCategory);
                this.OnDataRemoved(new DataEventArgs<Category>(true));
            }
        }

        public override void Update(Guid oldItemKey, Category newItem)
        {
            Category oldCategory = this.Get(oldItemKey);
            if (null == oldCategory)
            {
                this.Add(newItem);
            }
            else if (null == newItem)
            {
                this.OnDataUpdated(new DataUpdatedEventArgs<Category>(new ArgumentNullException("newItem")));
            }
            else
            {
                oldCategory.DisplayName = newItem.DisplayName;
                oldCategory.UpdatedDate = DateTime.Today;
                oldCategory.IsValid = newItem.IsValid;

                this.OnDataUpdated(new DataUpdatedEventArgs<Category>(true));
            }
        }

        public override void Save()
        {
            using (Stream saveDataStream = new FileStream(this.DataFilePath, FileMode.OpenOrCreate, FileAccess.Write))
            {
                this.InnerDataList.Serialize(saveDataStream);
            }
        }

        public override int Load()
        {
            if (!File.Exists(this.DataFilePath))
            {
                this.InnerDataList = new List<Category>();
            }
            else
            {
                using (Stream loadDataStream = new FileStream(this.DataFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite))
                {
                    this.InnerDataList = loadDataStream.Deserialize<List<Category>>();
                }
            }

            return this.InnerDataList.Count;
        }

        public override void Initialize()
        {
            base.InnerDataList = new List<Category>();
        }

        #endregion

        #region Implementation of IDataFileRepository

        public string DataFilePath { get; set; }

        #endregion

        #region Implementation of ICategoryRepository
        
        #endregion
    }
}
